#pragma once
#ifndef TENSORDENSECONSTRUCTORS_H_
#define TENSORDENSECONSTRUCTORS_H_

namespace cmpMat
{
    // set size
    template <typename _T>
    void TensorDense<_T>::SetSize()
    {
        _base::SetSize();
        _storage_array = _storage_array_type(0, 0);
    }
    template <typename _T>
    void TensorDense<_T>::SetSize(const CmpMatPtr& size1)
    {
        _base::SetSize(size1);
        _storage_array = _storage_array_type(size1, 0);
    }
    template <typename _T>
    void TensorDense<_T>::SetSize(const CmpMatPtr& size1, const CmpMatPtr& size2)
    {
        _base::SetSize(size1, size2);
        _storage_array = _storage_array_type(size1*size2, 0);
    }
    template <typename _T>
    void TensorDense<_T>::SetSize(const CmpMatPtr& size1, const CmpMatPtr& size2, const CmpMatPtr& size3)
    {
        _base::SetSize(size1, size2, size3);
        _storage_array = _storage_array_type(size1*size2*size3, 0);
    }
    template <typename _T>
    void TensorDense<_T>::SetSize(const CmpMatPtr& size1, const CmpMatPtr& size2, const CmpMatPtr& size3, const CmpMatPtr& size4)
    {
        _base::SetSize(size1, size2, size3, size4);
        _storage_array = _storage_array_type(size1*size2*size3*size4, 0);
    }

    // allows arbitrary rank
    template <typename _T>
    void TensorDense<_T>::SetSize(const _dimension_type& _dims)
    {
       _base::SetSize(_dims);
        CmpMatPtr elems = 1;
        for (_dimension_iterator iter = this->_dimensions.begin();
             iter != this->_dimensions.end();
             iter++)
        {
            elems *= *iter;
        }
        _storage_array = _storage_array_type(elems, 0);
    }

    // end set size

    template <typename _T>
    TensorDense<_T>* TensorDense<_T>::clone() const
    { return new TensorDense<_T>(*this); }

    template <typename _T>
    TensorDense<_T>::TensorDense()
    { SetSize(); }
    template <typename _T>
    TensorDense<_T>::TensorDense(const CmpMatPtr& size1)
    { SetSize(size1); }
    template <typename _T>
    TensorDense<_T>::TensorDense(const CmpMatPtr& size1, const CmpMatPtr& size2)
    { SetSize(size1, size2); }
    template <typename _T>
    TensorDense<_T>::TensorDense(const CmpMatPtr& size1, const CmpMatPtr& size2, const CmpMatPtr& size3)
    { SetSize(size1, size2, size3); }
    template <typename _T>
    TensorDense<_T>::TensorDense(const CmpMatPtr& size1, const CmpMatPtr& size2, const CmpMatPtr& size3, const CmpMatPtr& size4)
    { SetSize(size1, size2, size3, size4); }
    // allows arbitrary rank
    template <typename _T>
    TensorDense<_T>::TensorDense(const _dimension_type& _dims)
    { SetSize(_dims); }

    // copy constructors
    template <typename _T>
    TensorDense<_T>::TensorDense(const TensorDense<_T>& other)
    { *this = other; }
    template <typename _T>
    TensorDense<_T>::TensorDense(TensorDense<_T>&& other)
    { *this = std::move(other); }
    template <typename _T>
    TensorDense<_T> TensorDense<_T>::copyFrom(const TensorDense& other)
    { return TensorDense<_T>(other); }
    template <typename _T>
    TensorDense<_T> TensorDense<_T>::copyFrom(const TensorDense&& other)
    { return TensorDense<_T>(std::move(other)); }
    template <typename _T>
    TensorDense<_T> TensorDense<_T>::copyFrom(const TensorBase& other)
    {
        TensorDense<_T> out(other.Dimensions());
        Iterator iter1 = out.begin();
        const_Iterator iter2 = other.cbegin();
        for (;iter1 != out.end();++iter1,++iter2)
            *iter1 = *iter2;
        return out;
    }
}

#endif